package com.softa.shiro.spring;

import com.softa.cache.redis.RedisCache;
import com.softa.cache.redis.RedisCacheManager;
import com.softa.cache.redis.RedisCacheUtil;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.*;

/**
* @ClassName: SpringCacheManagerWrapper
* @Description: 包装Spring cache抽象
* @author yangl
* @date 2015-6-3 下午1:18:03
*
 */
@SuppressWarnings("all")
public class SpringCacheManagerWrapper implements CacheManager {

    private RedisCacheManager cacheManager;

    /**
     * 设置spring cache manager
     *
     * @param cacheManager
     */
    public void setCacheManager(RedisCacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }


    public <K, V> Cache<K, V> getCache(String name) throws CacheException {
        RedisCache springCache = cacheManager.getCache(name);
        return new SpringCacheWrapper(springCache);
    }

    static class SpringCacheWrapper implements Cache {
        private RedisCache springCache;

        SpringCacheWrapper(RedisCache springCache) {
            this.springCache = springCache;
        }


        public Object get(Object key) throws CacheException {
            Object value = springCache.get(key);
            if (value instanceof SimpleValueWrapper) {
                return ((SimpleValueWrapper) value).get();
            }
            return value;
        }


        public Object put(Object key, Object value) throws CacheException {
            springCache.put(key, value);
            return value;
        }


        public Object remove(Object key) throws CacheException {
            springCache.evict(key);
            return null;
        }


        public void clear() throws CacheException {
            springCache.clear();
        }


        public int size() {
            if(springCache.getNativeCache() instanceof RedisTemplate)
            {
                RedisCacheUtil memCache = springCache.getRedisCacheUtil();
                return memCache.getSize();
            } else
            {
                throw new UnsupportedOperationException("invoke spring cache abstract size method not supported");
            }
        }


        public Set keys() {
            if(springCache.getNativeCache() instanceof RedisTemplate)
            {
                RedisCacheUtil memCache = springCache.getRedisCacheUtil();
                return memCache.getKeySet();
            } else
            {
                throw new UnsupportedOperationException("invoke spring cache abstract keys method not supported");
            }
        }


        public Collection values() {
            if(springCache.getNativeCache() instanceof RedisTemplate)
            {
                Set keys = keys();
                if(!CollectionUtils.isEmpty(keys))
                {
                    List values = new ArrayList(keys.size());
                    for(Iterator iterator = keys.iterator(); iterator.hasNext();)
                    {
                        Object key = iterator.next();
                        Object value = get(key);
                        if(value != null)
                            values.add(value);
                    }

                    return Collections.unmodifiableList(values);
                } else
                {
                    return Collections.emptyList();
                }
            } else
            {
                throw new UnsupportedOperationException("invoke spring cache abstract values method not supported");
            }
        }
    }
}
